package com.tianlan.blog.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import com.tianlan.blog.dao.SysResourceDao;
import com.tianlan.blog.dao.SysRoleResourceDao;
import com.tianlan.blog.entity.SysResource;
import com.tianlan.blog.entity.SysRoleResource;
import com.tianlan.blog.service.SysResourceService;
import com.tianlan.common.base.BusinessException;

@Service
public class SysResourceServiceImpl implements SysResourceService{
	
	@Autowired
	private SysResourceDao sysResourceDao;
	
	@Autowired
	private SysRoleResourceDao sysRoleResourceDao;
	
	@Override
	@CacheEvict(value = "resources", allEntries = true)
	public boolean createResource(SysResource resource) {
		long isCount = sysResourceDao.countByResourceKeyAndDelFlag(resource.getResourceKey(),"0");
        if (isCount > 0) {
            throw new BusinessException("资源标识已存在");
        }
        resource = sysResourceDao.saveAndFlush(resource);
		return resource != null && !"".equals(resource);
	}
	
	@Override
	@CacheEvict(value = "resources", allEntries = true)
	public boolean updateResource(SysResource resource) {
		long isCount = sysResourceDao.countByIdAndDelFlag(resource.getId(),"0");
		if(isCount == 0){
	         throw new BusinessException("资源ID不存在");
		}
		resource = sysResourceDao.save(resource);
		sysResourceDao.flush();
		return resource != null && !"".equals(resource);
	}
	
	@Override
	public boolean deleteResource(Integer resourceId) {
		long isCount = sysResourceDao.countByIdOrParentIdAndDelFlag(resourceId,resourceId,"0");
		if(isCount == 0){
			throw new BusinessException("资源ID或父Id不存在");
		}
		int isRemove = sysResourceDao.remove(resourceId);
		return isRemove != 0;
	}
	
	@Override
	@Cacheable(value = "resources", key = "'role_id_'.concat(#roleId)")
	public List<SysResource> queryResourceByRoleId(Integer roleId) {
		List<SysRoleResource> roleResourceList = sysRoleResourceDao.findAllByRoleIdAndDelFlag(roleId,"0");
        if (!CollectionUtils.isEmpty(roleResourceList)) {
            List<Integer> resourceIds = new ArrayList<Integer>();
            for (SysRoleResource roleResource : roleResourceList) {
                resourceIds.add(roleResource.getResourceId());
            }
            List<SysResource> resourceList = sysResourceDao.getSysResource(resourceIds);
            return resourceList;
        } else {
            return null;
        }
	}
	
	@Override
	public List<SysResource> queryResourceByUserId(Integer userId) {
		List<SysResource> sysResourceList = sysResourceDao.queryResourceByUserId(userId);
		Map<Integer, SysResource> resourceMap = new HashMap<>();
		List<SysResource> menus = this.assembleResourceTree(sysResourceList,resourceMap);
		return menus;
	}

	@Override
	public List<String> queryResourceListByUserId(Integer userId) {
		List<SysResource> sysResourceList = sysResourceDao.queryResourceByUserId(userId);
        List<String> menus = new ArrayList<>();
        for (SysResource sysResource : sysResourceList) {
            menus.add(sysResource.getResourceKey());
        }
		return menus;
	}
	
    @Override
    @Cacheable(value = "resources", key = "'parent_id_'.concat(#parentId)")
	public List<SysResource> queryResourceByParentId(Integer parentId) {
        List<SysResource> resourceList = sysResourceDao.queryResourceTreeProc(parentId);
        Map<Integer, SysResource> resourceMap = new HashMap<>();
        List<SysResource> menus = this.assembleResourceTree(resourceList,resourceMap);
        return menus;
	}
    
    /**
     * 组装子父级目录
     * @param resourceList
     * @param resourceMap
     * @return
     */
    private List<SysResource> assembleResourceTree(List<SysResource> resourceList, Map<Integer, SysResource> resourceMap)
    {
        List<SysResource> menus = new ArrayList<>();
        for (SysResource resource : resourceList) {
            resourceMap.put(resource.getId(), resource);
        }
        for (SysResource resource : resourceList) {
            Integer treePId = resource.getParentId();
            SysResource resourceTree = resourceMap.get(treePId);
            if (null != resourceTree && !resource.equals(resourceTree)) {
                List<SysResource> nodes = resourceTree.getChildren();
                if (null == nodes) {
                    nodes = new ArrayList<>();
                    resourceTree.setChildren(nodes);
                }
                nodes.add(resource);
            } else {
                menus.add(resource);
            }
        }
        return menus;
    }

	
    @Override
	public long checkResourceKey(SysResource resource) {
    	@SuppressWarnings("serial")
    	Specification<SysResource> specification = new Specification<SysResource>() {
			@Override
			public Predicate toPredicate(Root<SysResource> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				String resourceKey = resource.getResourceKey();
				Predicate resourceKeyPredicate = cb.equal(root.get("resourceKey"), resourceKey);
				Predicate delFlagPredicate = cb.equal(root.get("delFlag"), "0");
				if (null != resource.getId()) {
					Predicate organizationIdPredicate = cb.notEqual(root.get("id"), resource.getId());
					return cb.and(resourceKeyPredicate, organizationIdPredicate, delFlagPredicate);
				}
				return cb.and(resourceKeyPredicate, delFlagPredicate);
			}
    	};
		return sysResourceDao.count(specification);
	}

}
